/**
 * 泛型：定义函数、接口或类的时候不直接指定类型，而是在使用的时候指定类型
 */

function fn<T>(args: T): T {
  return args
}

function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}

function fnArr<T>(arg: T[]): T[] {
  console.log(arg.length)
  return arg
}
let res = fn(123)
let res4 = fn('123')
let res5 = fn(true)
console.log(swap(['string', 123]))
console.log(fnArr([1,2,3,4]));

interface IWithLength {
  length: number
}

function fnWithLength<T extends IWithLength>(arg: T): T {
  console.log(arg.length)
  return arg
}

console.log(fnWithLength('DSAD'))
console.log(fnWithLength({length: 10})) // 只要有length属性就可以使用

class Queue<T> {
  private data = []
  push(item: T) {
    return this.data.push(item)
  }
  pop(): T {
    return this.data.shift()
  }
}

const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop())
const queue2 = new Queue<string>()
queue2.push('string')
console.log(queue2.pop())

interface KeyPair<T, U> {
  key: T;
  value: U;
}
let kp1: KeyPair<number, string> = {key: 123, value: 'string'}
let kp2: KeyPair<string, number> = {key: 'string', value: 123}

let arr: Array<number> = [1, 2, 3]

// 描述函数的类型
interface IFn<T> {
  (a: T, b: T): T
}

function plus(a: number, b: number): number {
  return a + b
}

function concat(a: string, b: string): string {
  return a + b
}
// 函数a的类型是IFn 和 plus的类型一致 所以可以赋值
const a: IFn<number> = plus
const b: IFn<string> = concat